<!--
 * @描述: 表格组件
 * @创建人: 高明超
 * @创建时间: 2022-04-27
 * @最后编辑人: 高明超
 * @最后编辑时间: 2023-02-14
 -->
<template>
  <div class="tn-data-table" :class="{ 'tn-data-table_full': isFull }">
    <!--表格头部工具栏-->
    <div v-if="slotHeader" class="tn-data-table-header">
      <slot name="header" v-bind="{ data: tableOptions.dataSource }" />
    </div>
    <!-- 表格主体 -->
    <Table v-bind="tableOptions" :key="tableKey + checkedColumns.length" @resizeColumn="handleResizeColumn">
      <template v-for="(_value, key) in slots" #[key]="slotProps" :key="key">
        <template v-if="key === 'bodyCell'">
          <TnTooltips
            v-if="slotProps.column?.showEllipsis"
            :key="slotProps.record"
            :content="slotProps.record?.[slotProps.column.dataIndex] ?? '--'"
            :max-width="
              tableOptions.expandIconColumnIndex || tableOptions.expandIconColumnIndex === 0
                ? handleDataTableColumns[tableOptions.expandIconColumnIndex].dataIndex === slotProps.column.dataIndex
                  ? 'calc(100% - 29px)'
                  : ''
                : ''
            "
          />
          <template v-else><slot :name="key" v-bind="slotProps"></slot></template>
        </template>
        <template v-else><slot :name="key" v-bind="slotProps"></slot></template>
      </template>
    </Table>
    <slot name="mySummary" v-bind="{ data: tableOptions.dataSource }"></slot>
    <div class="tn-data-table-footer">
      <div>
        <!-- 列设置 -->
        <Popover title="列显示" trigger="click" placement="topLeft">
          <template #content>
            <div class="tn-table-row-show">
              <CheckboxGroup v-model:value="checkedColumns" @change="columnsChange">
                <Checkbox
                  v-for="item in mycolumns"
                  :key="item.dataIndex"
                  :disabled="checkedColumns.length === 1 && checkedColumns.includes(item.dataIndex)"
                  :value="item.dataIndex"
                  class="m-0"
                >
                  {{ item.title }}
                </Checkbox>
              </CheckboxGroup>
            </div>
          </template>
          <Button size="small" type="text">
            <TableOutlined />
          </Button>
        </Popover>
        <!-- 刷新表格 -->
        <Tooltip>
          <template #title>刷新表格</template>
          <Button type="text" size="small" @click="reloadTable()">
            <ReloadOutlined />
          </Button>
        </Tooltip>
        <!-- 全屏 -->
        <Tooltip>
          <template #title>{{ isFull ? '退出全屏' : '全屏' }}</template>
          <Button type="text" size="small" @click="toggleFullScreen">
            <FullscreenOutlined v-if="!isFull" />
            <FullscreenExitOutlined v-if="isFull" />
          </Button>
        </Tooltip>
      </div>
      <div v-if="defaultTableOptions.needPagination">
        <Pagination
          v-model:current="paginationConfig.pageNum"
          v-model:page-size="paginationConfig.pageSize"
          :total="paginationConfig.total"
          show-size-changer
          :show-total="(total:number) => `共 ${total} 条`"
          @change="pageChange"
          @showSizeChange="pageSizeChange"
        />
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup name="tnDataTable">
import { Table, Popover, CheckboxGroup, Checkbox, Pagination, Tooltip, Button } from 'ant-design-vue'
import { computed, onMounted, PropType, reactive, ref, unref, useSlots, watch } from 'vue'
import { FullscreenOutlined, FullscreenExitOutlined, ReloadOutlined, TableOutlined } from '@ant-design/icons-vue'
import { ColumnType } from 'ant-design-vue/lib/table'
import { DataTableProps, ExtendedColumnsType } from './type'
import { useEventListener, useDebounceFn } from '@vueuse/core'
import TnTooltips from '@@/components/customShowTooltips.vue'

// const slotExpandedRowRender = !!useSlots().expandedRowRender

const emits = defineEmits(['dataUpdate', 'columnsChange'])

// 表格loading
const loading = ref(false)
// 判断header是否有内容
const slotHeader = !!useSlots().header

const slots = useSlots()

const { columns, tnTableProps, queryData, setTableDataFn } = defineProps({
  // 所有表格列配置
  columns: {
    type: [Array] as PropType<ExtendedColumnsType<any>>,
    required: true,
    default: () => []
  },
  // 表格所有的配置 DataTableProps里面加了几个自定义的字段
  tnTableProps: {
    type: Object as PropType<DataTableProps>,
    required: true,
    default: () => {}
  },
  queryData: {
    type: Object,
    default: () => null
  },
  setTableDataFn: {
    type: Function,
    default: null
  }
})

// 列change返回
const columnsChange = () => {
  emits('columnsChange', JSON.parse(JSON.stringify(handleDataTableColumns.value)))
}

const getTableColumns = () => {
  return JSON.parse(JSON.stringify(handleDataTableColumns.value))
}

// row-class-name设置
const rowClassName = (_record: any, index: number) => (index % 2 === 0 ? 'table-striped' : null)

// 合并参数 defaultTableOptions默认参数
let defaultTableOptions: DataTableProps = {
  showNo: true, // 是否显示序号
  pagination: false, // 是否需要分页
  maxheight: 480, // 表格最大高度
  needPagination: true, // 是否需要分页
  initRequest: true, // 是否需要初始化请求
  isResizeWidth: true // 是否支持拖动调整宽度
}
defaultTableOptions = Object.assign(defaultTableOptions, tnTableProps)
//判断外部是否传入新的rowclassname参数，如果传入，需要把斑马纹合并进去
if (defaultTableOptions.rowClassName) {
  defaultTableOptions.rowClassName = function (_record: any, index: number) {
    return (defaultTableOptions as any).rowClassName(_record, index) + ' ' + rowClassName(_record, index)
  }
} else {
  ;(defaultTableOptions as any).rowClassName = rowClassName
}

// 提取常用变量
const { asyncApi, tableData, showNo, initRequest, isResizeWidth } = defaultTableOptions
// 表格固定高度, 默认480
const scroll = reactive({ y: 480 })

// 列设置
let mycolumns: any = columns
// 如果需要序号
if (showNo) {
  const findIndex = mycolumns.findIndex((item: ColumnType<any>) => item.dataIndex === 'rowNo')
  if (findIndex === -1) {
    mycolumns.unshift({
      title: '序号',
      dataIndex: 'rowNo',
      align: 'center',
      width: 60,
      fixed: 'left'
    })
  }
}

// 设置列是否可以拖动
if (isResizeWidth) {
  mycolumns = mycolumns.map((item: any) => {
    // 如果该列已经设置了，就不再设置
    if ('resizable' in item) {
      return item
    }
    item.resizable = true
    return item
  })
}
const handleResizeColumn = (w: number, col: any) => {
  col.width = w
}

console.log('mycolumns', mycolumns)

// 列设置，选中所有列
const checkedColumns = ref(mycolumns.filter((item) => !item.hidden).map((item: any) => item.dataIndex))

// 刷新表格
const reloadTable = (pageNum?: number) => {
  handleAsyncData(pageNum || paginationConfig.pageNum)
}

// 根据选中的列显示
// const handleDataTableColumns = computed(() => {
//   const checkedArr = unref(checkedColumns)
//   return mycolumns.filter((item: ColumnType) => checkedArr.includes(item.dataIndex))
// })
const handleDataTableColumns = ref<any[]>([])
watch(
  [() => checkedColumns, () => mycolumns],
  ([checkedColumns, mycolumns]) => {
    console.log()
    const checkedArr = unref(checkedColumns)
    handleDataTableColumns.value = mycolumns.filter((item: ColumnType) => checkedArr.includes(item.dataIndex))
  },
  {
    deep: true,
    immediate: true
  }
)

// 绑定表单属性
const tableOptions = computed(() => {
  const dataSource = unref(handleTableData)
  defaultTableOptions = Object.assign(defaultTableOptions, tnTableProps)
  return {
    ...defaultTableOptions,
    dataSource,
    columns: unref(handleDataTableColumns),
    loading: unref(loading),
    scroll
  }
})

// 分页设置
const paginationConfig = reactive({
  pageNum: 1,
  pageSize: 10,
  total: 0,
  pageSizes: [10, 20, 30, 40, 50]
})

// 处理table的data数据
const handleTableData = ref(tableData || [])

// 处理异步数据
const tableKey = ref()
const handleAsyncData = async (pageNum: number): Promise<void> => {
  const fn = asyncApi || (() => Promise.resolve())
  loading.value = true

  const res = await fn(
    Object.assign(
      {
        pageNum,
        pageSize: paginationConfig.pageSize
      },
      queryData
    )
  ).catch(() => {
    loading.value = false
  })

  loading.value = false
  if (!res) {
    return
  }
  let list: any[] = []
  if (defaultTableOptions.needPagination) {
    list = res.list || []
    paginationConfig.pageNum = pageNum
    paginationConfig.total = Number(res.total)
    // 这里来处理，实际只有10页，但是传入pageNum为11时，重置一下pageNum
    if (res.pages < res.pageNum && res.pages) {
      paginationConfig.pageNum = res.pages
      handleAsyncData(res.pages)
      return
    }
  } else {
    list = res || []
  }
  if (setTableDataFn && typeof setTableDataFn === 'function') {
    list = setTableDataFn(list)
  }
  list = list.map((item: any, index: number) => {
    return {
      ...item,
      rowNo: (pageNum - 1) * paginationConfig.pageSize + index + 1
    }
  })
  handleTableData.value = list
  tableKey.value = Math.random()
  emits('dataUpdate', {
    tableData: JSON.parse(JSON.stringify(handleTableData.value)),
    queryData: queryData,
    paginationConfig: paginationConfig
  })
}

// 如果asyncApi存在，则请求数据
if (asyncApi && initRequest) {
  handleAsyncData(1)
}

// 切换页
const pageChange = (pageNum: number) => {
  handleAsyncData(pageNum)
}

// 分页大小变化
const pageSizeChange = function () {
  paginationConfig.pageNum = 1
  paginationConfig.pageSize = arguments[1]
  handleAsyncData(1)
}

// 全面切换
const isFull = ref(false)

// 监听全屏切换事件
useEventListener(document, 'fullscreenchange', () => {
  isFull.value = document.fullscreenElement !== null ? true : false
})

const toggleFullScreen = () => {
  if (!document.fullscreenElement) {
    document.documentElement.requestFullscreen()
  } else if (document.exitFullscreen) {
    document.exitFullscreen()
  }
}

const resizeObserverMainBox = new ResizeObserver(() => {
  const el = document.querySelector('.layout-head-tips')
  if (el) {
    tipsHeight.value = (el as any).offsetHeight
  } else {
    tipsHeight.value = 0
  }
  handler()
})

// 设置表格的高度
let handler = () => {
  console.log('otherTabelHeight', defaultTableOptions.otherTabelHeight, isFull.value)
  if (!isFull.value) {
    if (defaultTableOptions.otherTabelHeight) {
      scroll.y = window.innerHeight - (defaultTableOptions.otherTabelHeight as number) - tipsHeight.value
    } else {
      scroll.y = defaultTableOptions.maxheight as number
    }
  } else {
    scroll.y = window.innerHeight - 200
  }
}
handler = useDebounceFn(handler, 200)
useEventListener(window, 'resize', handler)
const tipsHeight = ref(0)
onMounted(() => {
  const el: any = document.querySelector('.layout-head-tips')
  if (el) {
    resizeObserverMainBox.observe(el)
    tipsHeight.value = el.offsetHeight
  } else {
    handler()
  }
})

// 获取表格的数据
function getTableData() {
  return {
    commonData: JSON.parse(JSON.stringify(unref(handleTableData))),
    ProxyData: unref(handleTableData)
  }
}

// 暴露给父组件的方法
defineExpose({
  reloadTable,
  getTableData,
  handleDataTableColumns,
  getTableColumns,
  paginationConfig
})
</script>

<style lang="less">
.tn-data-table {
  background-color: #fff;
  border-radius: 6px;
  overflow: hidden;

  .tn-data-table-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid #f0f0f0;
    padding: 12px;

    .ant-btn {
      margin: 0 6px;
    }
  }
  .ant-table-cell .ant-btn {
    padding: 4px 6px;
  }

  &.tn-data-table_full {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 100%;
    z-index: 99;
  }

  // 斑马纹设置
  .ant-table-tbody > tr.table-striped > td {
    background: #f2f8ff;
  }

  // 划过设置
  .ant-table-tbody > tr.ant-table-row:hover,
  .ant-table-tbody > tr > td.ant-table-cell-row-hover {
    transition: none;
    background: #d9ebff !important;
  }

  .ant-table-thead > tr > th,
  .ant-table-tbody > tr > td {
    padding: 12px;
    border-color: transparent;
  }

  // 表头
  .ant-table-thead > tr > th {
    background: #fff;
    color: #999;
    font-weight: bold;
    padding: 18px 12px;
  }

  // .ant-table-thead
  //   > tr
  //   > th:not(:last-child):not(.ant-table-selection-column):not(
  //     .ant-table-row-expand-icon-cell
  //   ):not([colspan])::before {
  //   display: none;
  // }

  // 表格底部
  .tn-data-table-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px;
  }

  // .ant-table-cell-with-append {
  //   display: flex;
  //   align-items: center;
  // }
}

.tn-table-row-show {
  width: 180px;

  .ant-checkbox-wrapper {
    display: flex;
  }

  .ant-checkbox-wrapper + .ant-checkbox-wrapper {
    margin: 0;
  }
}
</style>
